#ifndef _TEST_CLIENT_1_
#define _TEST_CLIENT_1_

#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include <boost/noncopyable.hpp>
#include <iostream>

using namespace boost::asio;

class TestClient : public boost::enable_shared_from_this<TestClient>, boost::noncopyable
{
public:
    TestClient() = default;
    TestClient(io_context &context) : context_(context), sock(context), heartbeatTimer(context, boost::asio::chrono::seconds(heartBeatInternal)) {};
    ~TestClient() = default;

private:
    io_context &context_;
    ip::tcp::socket sock;
    steady_timer heartbeatTimer;
    std::string ip_ = "127.0.0.1";
    unsigned int port_ = 9000;

    enum
    {
        heartBeatInternal = 5,
        read_buf_size = 1024
    };
    char buf[read_buf_size];

public:
    void setIp(std::string ip, unsigned int port)
    {
        this->ip_ = ip;
        this->port_ = port;
    }
    void do_connect()
    {
        ip::address addr = ip::address::from_string(ip_);
        ip::tcp::endpoint ep(addr, port_);

        sock.async_connect(ep, boost::bind(&TestClient::connect_handler, shared_from_this(), _1));
    }
    void connect_handler(const boost::system::error_code &err)
    {
        if (err)
        {
            std::cout << "connect error" << err.message() << std::endl;
            return;
        }

        // 发送心跳
        heartbeatTimer.async_wait(boost::bind(&TestClient::sendHeartBeat, shared_from_this(), _1));

        // do_write 测试
        do_write();

        // 连接成功开始尝试读取数据
        do_read();
    }
    void sendHeartBeat(const boost::system::error_code &err)
    {
        if (err)
        {
            std::cout << "sendHeartBeat err " << err.message() << err.value() << std::endl;
            close();
            return;
        }
        // todo
        sock.write_some(buffer("ping..."));

        // 重置定时器，达到周期性执行的效果
        heartbeatTimer.expires_at(heartbeatTimer.expiry() + boost::asio::chrono::seconds(heartBeatInternal));
        heartbeatTimer.async_wait(boost::bind(&TestClient::sendHeartBeat, shared_from_this(), _1));
    }
    void do_read()
    {
        sock.async_read_some(buffer(buf), boost::bind(&TestClient::readHandler, this, _1, _2));
    }
    void readHandler(const boost::system::error_code &err, std::size_t bytes)
    {
        // stream被关闭
        if (err == boost::asio::error::eof)
        {
            std::cerr << "boost::asio::error::eof." << std::endl;
            close();
            return;
        }

        // todo 处理消息
        std::cout << "read bytes >>>" << bytes << std::endl;
        std::cout << "msg --->" << std::string(buf, 0, bytes) << std::endl;

        do_read();
    }
    void do_write()
    {
        try
        {
            sock.write_some(buffer("hello world"));
        }
        catch (const std::exception &e)
        {
            std::cerr << "client write error >>>" << e.what() << '\n';
            close();
            return;
        }
    }
    void write() {}
    void close()
    {
        std::cout << "disconnected..." << std::endl;
        // 停止 io_context 上所有正在运行的异步操作
        context_.stop();
        if (sock.is_open())
        {
            sock.close();
        }
    }
};

#endif